/*
Copyright 2025 PerfXLab (Beijing) Technologies Co., Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include "OpenSparseBLAS_type.h"

#ifdef __cplusplus
extern "C"
{
#endif

    /**
     * @defgroup core
     * @brief OpenSparseBLAS objects
     * @details Definition and basic operation of OpenSparseBLAS objects.
     * @{
     */

    /**
     * @brief OpenSparseBLAS initialization function
     * @details An instance of the SparseBLAS C API implementation as seen by an application. An application can have only one context between the start and end of the application. A context begins with the first thread that calls \link OpenSpB_init \endlink and ends with the first thread to call \link OpenSpB_finalize \endlink. It is an error for \link OpenSpB_init \endlink or \link OpenSpB_finalize \endlink to be called more than one time within an application.
     */
    void OpenSpB_init();
    /**
     * @brief OpenSparseBLAS finalization  function
     * @details An instance of the SparseBLAS C API implementation as seen by an application. An application can have only one context between the start and end of the application. A context begins with the first thread that calls \link OpenSpB_init \endlink and ends with the first thread to call \link OpenSpB_finalize \endlink. It is an error for \link OpenSpB_init \endlink or \link OpenSpB_finalize \endlink to be called more than one time within an application.
     */
    void OpenSpB_finalize();

    /**
     * @defgroup OpenSpB_scalar
     * @brief OpenSpB_scalar class
     * @{
     */

    /**
     * @brief Creates a new empty scalar with specified domain.
     * @param[in,out] s On successful return, contains a handle to the newly created OpenSparseBLAS scalar.
     * @param[in] d The type corresponding to the domain of the scalar being created.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_scalar_new(OpenSpB_scalar *s, OpenSpB_type type);

    /**
     * @brief Destroys a previously created OpenSpB_scalar object and releases any resources associated with the object.
     *
     * @param[in,out] s An existing OpenSpB_vector object to be destroyed. The object must have been created by an explicit call to a \link OpenSpB_scalar_new \endlink constructor. On successful completion of OpenSpB_scalar_free, obj behaves as an uninitialized object.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_scalar_free(OpenSpB_scalar *s);

    ///@}

    /**
     * @defgroup OpenSpB_vector
     * @brief OpenSpB_vector class
     * @details OpenSpB_vector is inherited as a base class by \link OpenSpB_vector_Sparse \endlink and \link OpenSpB_vector_Dense \endlink. They represent the storage of vector elements in sparse and dense formats, respectively.
     * @{
     */

    /**
     * @brief Creates a new vector with specified domain and size
     * @param[in,out] v On successful return, contains a handle to the newly created OpenSparseBLAS vector
     * @param[in] type The type corresponding to the domain of the vector being created. Can be one of the predefined SparseBLAS types in \link OpenSpB_type \endlink.
     * @param[in] n The size of the vector being created.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_vector_new(OpenSpB_vector *v, OpenSpB_type type, OpenSpB_index n);

    /**
     * @brief Destroys a previously created OpenSpB_vector object and releases any resources associated with the object.
     *
     * @param[in,out] v An existing OpenSpB_vector object to be destroyed. The object must have been created by an explicit call to a \link OpenSpB_vector_new \endlink constructor. On successful completion of OpenSpB_vector_free, obj behaves as an uninitialized object.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_vector_free(OpenSpB_vector *v);

    /**
     * @brief Creates a new vector with the same domain, size, and contents as another vector
     * @param[in,out] v1 successful return, contains a handle to the newly created OpenSparseBLAS vector.
     * @param[in] v2 The OpenSparseBLAS vector to be duplicated.
     */
    OpenSpB_info OpenSpB_vector_dup(OpenSpB_vector *v1, OpenSpB_vector v2);

    /**
     * @brief Retrieve the number of stored elements (tuples) in a vector.
     * @param[out] nvals On successful return, this is set to the number of stored elements (tuples) in the vector.
     * @param[in] v An existing SparseBLAS vector being queried.
     */
    OpenSpB_info OpenSpB_vector_nvals(OpenSpB_index *nvals, OpenSpB_vector v);

    //------------------------------------------------------------------------------
    // OpenSpB_vector_build
    //------------------------------------------------------------------------------

    // OpenSpB_vector_build:  C = sparse (I,X), but using any
    // associative operator to assemble duplicate entries.

    /**
     * @anchor OpenSpB_vector_build
     * @name OpenSpB_vector_build
     * @brief Store elements from tuples into a vetctor
     * @details
     * @brief Store elements from tuples into a vetctor
     *
     * @param[in,out] w An existing Vector object to store the result.
     * @param[in] indices Pointer to an array of indices.
     * @param[in] values Pointer to an array of scalars of a type that is compatible with the domain of vector **w**.
     * @param[in] n The number of entries contained in each array (the same for indices and values).
     * @return OpenSpB_info
     */
    ///@{
    /**
     * @brief Store BOOL elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_vector_build for function introduction details
     */
    // TODO: rename?
    OpenSpB_info OpenSpB_vector_build_BOOL(
        OpenSpB_vector w,
        const OpenSpB_index *indices,
        const bool *values,
        OpenSpB_index n);

    /**
     * @brief Store INT32 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_vector_build for function introduction details
     */
    OpenSpB_info OpenSpB_vector_build_INT32(
        OpenSpB_vector w,
        const OpenSpB_index *indices,
        const int32_t *values,
        OpenSpB_index n);
    ///@}

    //------------------------------------------------------------------------------
    // OpenSpB_vector_set_element
    //------------------------------------------------------------------------------

    // Set a single scalar in a vector, w(i) = x, typecasting from the type of x to
    // the type of w as needed.

    /**
     * @anchor OpenSpB_vector_set_element
     * @name OpenSpB_vector_set_element
     * @brief Set one element of a vector to a given value.
     * @param[in,out] w An existing SparseBLAS vector for which an element is to be assigned.
     * @param[in] x Scalar assign. Its domain (type) must be compatible with the domain of w.
     * @param[in] i The location of the element to be assigned.
     * @return OpenSpB_info
     */
    ///@{
    /**
     * @brief Set a single OpenSpB_scalar element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_Scalar // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            OpenSpB_scalar s, // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );
    /**
     * @brief Set a single BOOL element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_BOOL // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            bool x,           // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single INT8 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_INT8 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            int8_t x,         // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single UINT8 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_UINT8 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            uint8_t x,        // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single INT16 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_INT16 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            int16_t x,        // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single UINT16 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_UINT16 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            uint16_t x,       // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single INT32element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_INT32 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            int32_t x,        // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single UINT32 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_UINT32 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            uint32_t x,       // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single INT64 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_INT64 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            int64_t x,        // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single UINT64 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_UINT64 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            uint64_t x,       // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single FP32 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_FP32 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            float x,          // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );

    /**
     * @brief Set a single FP64 element in a vector
     * @details Please refer to \ref OpenSpB_vector_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_set_element_FP64 // w(i) = x
        (
            OpenSpB_vector w, // vector to modify
            double x,         // scalar to assign to w(i)
            OpenSpB_index i   // row index
        );
    ///@}
    // Type-generic version:  x can be any supported C type or void * for a
    // user-defined type.

    //------------------------------------------------------------------------------
    // OpenSpB_vector_extract_element
    //------------------------------------------------------------------------------

    // Extract a single entry from a vector, x = v(i), typecasting from the type of
    // v to the type of x as needed.

    /**
     * @anchor OpenSpB_vector_extract_element
     * @name OpenSpB_vector_extract_element
     * @brief Extract a single element from a vector.
     * @param[in,out] x An existing scalar of whose domain is compatible with the domain of vector v. On successful return, this scalar holds the result of the extract.
     * @param[in] v The OpenSparseBLAS vector from which an element is extracted.
     * @param[in] i The location in v to extract.
     * @return OpenSpB_info
     */
    ///@{

    /**
     * @brief Extract a single OpenSpB_scalar element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_Scalar // x = v(i)
        (
            OpenSpB_scalar x,       // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single BOOL element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_BOOL // x = v(i)
        (
            bool *x,                // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single INT8 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_INT8 // x = v(i)
        (
            int8_t *x,              // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single UINT8 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_UINT8 // x = v(i)
        (
            uint8_t *x,             // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single INT16 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_INT16 // x = v(i)
        (
            int16_t *x,             // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single UINT16 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_UINT16 // x = v(i)
        (
            uint16_t *x,            // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single INT32 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_INT32 // x = v(i)
        (
            int32_t *x,             // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single UINT32 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_UINT32 // x = v(i)
        (
            uint32_t *x,            // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single INT64 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_INT64 // x = v(i)
        (
            int64_t *x,             // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single UINT64 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_UINT64 // x = v(i)
        (
            uint64_t *x,            // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single FP32 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_FP32 // x = v(i)
        (
            float *x,               // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    /**
     * @brief Extract a single FP64 element from a vector.
     * @details Please refer to \ref OpenSpB_vector_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_element_FP64 // x = v(i)
        (
            double *x,              // scalar extracted
            const OpenSpB_vector v, // vector to extract an entry from
            OpenSpB_index i         // row index
        );

    ///@}
    // Type-generic version:  x can be a pointer to any supported C type or void *
    // for a user-defined type.

    //------------------------------------------------------------------------------
    // OpenSpB_vector_extract_tuples
    //------------------------------------------------------------------------------

    // Extracts all tuples from a vector, like [I,~,X] = find (v).  If
    // any parameter I and/or X is NULL, then that component is not extracted.  For
    // example, to extract just the row indices, pass I as non-NULL, and X as NULL.
    // This is like [I,~,~] = find (v).

    /**
     * @anchor OpenSpB_vector_extract_tuples
     * @name OpenSpB_vector_extract_tuples
     * @brief Extract tuples from a vector
     * @param[out] RowInd Pointer to an array of indices that is large enough to hold all of the stored values’ indices.
     * @param[out] Vals Pointer to an array of scalars of a type that is large enough to hold all of the stored values whose type is compatible with D(v).
     * @param[in] nvals Pointer to a value indicating (on input) the number of elements the values and indices arrays can hold. Upon return, it will contain the number of values written to the arrays.
     * @param[in] v An existing OpenSparseBLAS vector.
     * @return OpenSpB_info
     */
    ///@{
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_BOOL // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            bool *Vals,               // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );

    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_INT8 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            int8_t *Vals,             // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_UINT8 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            uint8_t *Vals,            // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_INT16 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            int16_t *Vals,            // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_UINT16 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            uint16_t *Vals,           // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_INT32 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            int32_t *Vals,            // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_UINT32 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            uint32_t *Vals,           // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_INT64 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            int64_t *Vals,            // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_UINT64 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            uint64_t *Vals,           // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_FP32 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            float *Vals,              // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    /**
     * @brief Extract the contents of a OpenSparseBLAS vector into non-opaque data structures.
     * @details Please refer to \ref OpenSpB_vector_extract_tuples for function introduction details
     */
    OpenSpB_info OpenSpB_vector_extract_tuples_FP64 // [I,~,X] = find (v)
        (
            OpenSpB_index *RowInd,      // array for returning row indices of tuples
            double *Vals,             // array for returning values of tuples
            OpenSpB_index *nvals,  // I, X size on input; # tuples on output
            const OpenSpB_vector v // vector to extract tuples from
        );
    ///@}
    // Type-generic version:  X can be a pointer to any supported C type or void *
    // for a user-defined type.

    /**@}*/ // end for OpenSpB_vector

    /**
     * @defgroup OpenSpB_matrix
     * @brief OpenSpB_matrix class
     * @{
     */

    /**
     * @brief Get the data type of a matrix
     *
     * @param[out] t On successful return, contains the result type of the input matrix.
     * @param[in] m An existing OpenSparseBLAS matrix being queried.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_type(OpenSpB_type *t, OpenSpB_matrix m);
    /**
     * @brief Number of rows in a matrix
     * @details Retrieve the number of rows in a matrix.
     * @param[out] n On successful return, contains the number of rows in the matrix.
     * @param[in] m An existing OpenSparseBLAS matrix being queried.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_nrows(OpenSpB_index *n, OpenSpB_matrix m);

    /**
     * @brief Number of columns in a matrix
     * @details Retrieve the number of columns in a matrix
     *
     * @param n On successful return, contains the number of columns in the matrix.
     * @param m An existing OpenSparseBLAS matrix being queried.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_ncols(OpenSpB_index *n, OpenSpB_matrix m);

    /**
     * @brief Construct new matrix
     * @details Creates a new matrix with specified domain and dimensions.
     * @param[in,out] m On successful return, contains a handle to the newly created OpenSparseBLAS matrix.
     * @param[in] type The type corresponding to the domain of the matrix being created. Can be one of the predefined \link OpenSpB_type \endlink.
     * @param[in] nrows The number of rows of the matrix being created.
     * @param[in] ncols The number of columns of the matrix being created.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_new(OpenSpB_matrix *m, OpenSpB_type type, OpenSpB_index nrows, OpenSpB_index ncols);

    /**
     * @brief Destroy a matrix and release its resources
     * @details Destroys a previously created OpenSparseBLAS matrix object and releases any resources associated with the matrix.
     * @param[in,out] A An existing SparseBLAS matrix to be destroyed. The object must have been created by an explicit call to a OpenSparseBLAS matrix constructor. On successful completion, matrix A behaves as an uninitialized matrix object.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_free(OpenSpB_matrix *A);

    //------------------------------------------------------------------------------
    // OpenSpB_matrix_build
    //------------------------------------------------------------------------------

    /**
     * @anchor OpenSpB_matrix_build
     * @name OpenSpB_matrix_build
     * @brief Store elements from tuples into a matrix
     * @details
     * @brief Store elements from tuples into a matrix
     *
     * @param[in,out] C An existing Matrix object to store the result.
     * @param[in] RowInd Pointer to an array of row indices.
     * @param[in] ColInd Pointer to an array of column indices.
     * @param[in] X Pointer to an array of scalars of a type that is compatible with the domain of matrix, C.
     * @param[in] nvals The number of entries contained in each array (the same for row_indices, col_indices and values).
     * @param[in] dup An associative and commutative binary operator to apply when duplicate values for the sam  location are present in the input arrays.
     * @return OpenSpB_info
     */
    ///@{
    /**
     * @brief Store BOOL elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_BOOL // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const bool *Vals,          // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT8 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_INT8 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int8_t *Vals,        // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT8 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_UINT8 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint8_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT16 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_INT16 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int16_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT16 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_UINT16 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint16_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT32 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_INT32 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int32_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT32 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_UINT32 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint32_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT64 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_INT64 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int64_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT64 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_UINT64 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint64_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store FP32 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_FP32 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const float *Vals,         // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store FP64 elements from tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_build for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_build_FP64 // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const double *Vals,        // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );
    ///@}

    /**
       * @anchor OpenSpB_matrix_fast_build_ext
       * @name OpenSpB_matrix_fast_build_ext
       * @brief Store elements from sorted tuples into a matrix
       * @details If the incoming tuples are ordered (in order of CSC or CSR format), the matrix created by calling this interface can be created more quickly. This is because the interface can make direct copies of ordered tuples, eliminating the need to sort incoming tuples. \n <b>However, it is worth noting that the sorting rules must be consistent with the format of the SparseBLAS matrix, otherwise it will lead to undefined errors. Passing in unsorted tuples will also result in undefined errors. Therefore, it is recommended to call this interface with caution.</b>

       *
       * @param[in,out] C An existing Matrix object to store the result.
       * @param[in] RowInd Pointer to an array of sorted row indices.
       * @param[in] ColInd Pointer to an array of sorted column indices.
       * @param[in] X Pointer to an array of sorted scalars of a type that is compatible with the domain of matrix, C.
       * @param[in] nvals The number of entries contained in each array (the same for row_indices, col_indices and values).
       * @param[in] dup An associative and commutative binary operator to apply when duplicate values for the sam  location are present in the input arrays.
       * @return OpenSpB_info
       */
    ///@{
    /**
     * @brief Store BOOL elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_BOOL_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const bool *Vals,          // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT8 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_INT8_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int8_t *Vals,        // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT8 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_UINT8_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint8_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT16 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_INT16_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int16_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT16 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_UINT16_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint16_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT32 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_INT32_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int32_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT32 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_UINT32_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint32_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store INT64 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_INT64_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const int64_t *Vals,       // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store UINT64 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_UINT64_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const uint64_t *Vals,      // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store FP32 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_FP32_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const float *Vals,         // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );

    /**
     * @brief Store FP64 elements from sorted tuples into a matrix
     * @details Please refer to \ref OpenSpB_matrix_fast_build_ext for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_fast_build_FP64_ext // build a matrix from (RowInd,ColInd,Vals) tuples
        (
            OpenSpB_matrix Mat,       // matrix to build
            const OpenSpB_index *RowInd, // array of row indices of tuples
            const OpenSpB_index *ColInd, // array of column indices of tuples
            const double *Vals,        // array of values of tuples
            OpenSpB_index nvals     // number of tuples
        );
    ///@}

    //------------------------------------------------------------------------------
    // OpenSpB_matrix_set_element
    //------------------------------------------------------------------------------

    // Set a single entry in a matrix, Mat(i,j) = x, typecasting
    // from the type of x to the type of C, as needed.

    /**
     * @anchor OpenSpB_matrix_set_element
     * @name  OpenSpB_matrix_set_element
     * @brief Set a single element in matrix
     * @details Set one element of a matrix to a given value.
     * @param[in,out] Mat An existing OpenSparseBLAS matrix for which an element is to be assigned.
     * @param[in] x Scalar to assign. Its domain (type) must be compatible with the domain of C.
     * @param[in] i Row index of element to be assigned
     * @param[in] j Column index of element to be assigned
     * @return OpenSpB_info
     */

    ///@{

    /**
     * @brief Set a single BOOL element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_BOOL // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            bool x,           // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single INT8 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_INT8 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            int8_t x,         // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single UINT8 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_UINT8 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            uint8_t x,        // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single INT16 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_INT16 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            int16_t x,        // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single UINT16 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_UINT16 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            uint16_t x,       // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single INT32 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_INT32 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            int32_t x,        // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );
    /**
     * @brief Set a single UINT32 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_UINT32 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            uint32_t x,       // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );
    /**
     * @brief Set a single INT64 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_INT64 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            int64_t x,        // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );
    /**
     * @brief Set a single UINT64 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_UINT64 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            uint64_t x,       // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single FP32 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_FP32 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            float x,          // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );

    /**
     * @brief Set a single FP64 element in matrix
     * @details Please refer to \ref OpenSpB_matrix_set_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_set_element_FP64 // Mat (i,j) = x
        (
            OpenSpB_matrix Mat, // matrix to modify
            double x,         // scalar to assign to Mat(i,j)
            OpenSpB_index i,  // row index
            OpenSpB_index j   // column index
        );
    ///@}
    // Type-generic version:  x can be any supported C type or void * for a
    // user-defined type.

#if OpenSpB_STDC_VERSION >= 201112L
#define OpenSpB_matrix_set_element(C, x, i, j) \
    _Generic(                                 \
        (x),                                  \
        OpenSpB_CASES(, OpenSpB, Matrix_setElement))(C, x, i, j)
#endif

    //------------------------------------------------------------------------------
    // OpenSpB_matrix_extract_element
    //------------------------------------------------------------------------------

    // Extract a single entry from a matrix, x = A(i,j), typecasting from the type
    // of A to the type of x, as needed.

    /**
     * @anchor OpenSpB_matrix_extract_element
     * @name OpenSpB_matrix_extract_element
     * @brief Extract a single element from a matrix
     * @details Extract one element of a matrix into a scalar.
     * @param[in,out] x An existing scalar whose domain is compatible with the domain of matrix A. On successful return, this scalar holds the result of the extract. Any previous value stored in val or s is overwritten.
     * @param[in] A The OpenSparseBLAS matrix from which an element is extracted.
     * @param[in] i The row index of location in A to extract.
     * @param[in] j The column index of location in A to extract.
     * @return OpenSpB_info
     */

    ///@{

    /**
     * @brief Extract a single OpenSpB_scalar element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_Scalar // x = A(i,j)
        (
            OpenSpB_scalar x,       // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );

    /**
     * @brief Extract a single BOOL element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_BOOL // x = A(i,j)
        (
            bool *x,                // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );

    /**
     * @brief Extract a single INT8 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_INT8 // x = A(i,j)
        (
            int8_t *x,              // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single UINT8 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_UINT8 // x = A(i,j)
        (
            uint8_t *x,             // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single INT16 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_INT16 // x = A(i,j)
        (
            int16_t *x,             // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single UINT16 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_UINT16 // x = A(i,j)
        (
            uint16_t *x,            // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single INT32 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_INT32 // x = A(i,j)
        (
            int32_t *x,             // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single UINT32 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_UINT32 // x = A(i,j)
        (
            uint32_t *x,            // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single INT64 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_INT64 // x = A(i,j)
        (
            int64_t *x,             // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single UINT64 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_UINT64 // x = A(i,j)
        (
            uint64_t *x,            // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single FP32 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_FP32 // x = A(i,j)
        (
            float *x,               // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    /**
     * @brief Extract a single FP64 element from a matrix
     * @details Please refer to \ref OpenSpB_matrix_extract_element for function introduction details
     */
    OpenSpB_info OpenSpB_matrix_extract_element_FP64 // x = A(i,j)
        (
            double *x,              // extracted scalar
            const OpenSpB_matrix A, // matrix to extract a scalar from
            OpenSpB_index i,        // row index
            OpenSpB_index j         // column index
        );
    ///@} //end for OpenSpB_matrix_extract_element
    // Type-generic version:  x can be a pointer to any supported C type or void *
    // for a user-defined type.

    /**@}*/ // end for OpenSpB_matrix
    /**@}*/ // end for core

    /**
     * @defgroup operator
     * @brief The basic operations of OpenSparseBLAS
     * @details This module contains the basic operations of OpenSparseBLAS
     * @{
     */

    /**
     * @defgroup OpenSpB_mxv
     * @brief Matrix-Vector multiplication module
     * @details This module mainly implements OpenSpB_mxv, whose core operators are SpMSpV and SpMV, both of which are very important for graph algorithms to achieve Pull/Push optimization \cite yang2018implementing.
     * @{
     */
    OpenSpB_info OpenSpB_SpMV_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_VNEC_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_EDA_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_PCSR_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_PCSR_W_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);
    OpenSpB_info OpenSpB_SpMV_Adaptive_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_MERGE_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_LBNEC_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_Nec_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_LIGHT_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_LINE_ENHANCE_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);


    OpenSpB_info OpenSpB_SpMV_ACSR_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_flat_FP32(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

                        
    OpenSpB_info OpenSpB_SpMV_FP64(OpenSpB_operation_t op,
                                     const void *alpha,
                                     const OpenSpB_matrix matA,
                                     const OpenSpB_vector vecX,
                                     const void *beta,
                                     OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_PCSR_FP64(OpenSpB_operation_t op,
                                        const void *alpha,
                                        const OpenSpB_matrix matA,
                                        const OpenSpB_vector vecX,
                                        const void *beta,
                                        OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_Adaptive_FP64(OpenSpB_operation_t op,
                                        const void *alpha,
                                        const OpenSpB_matrix matA,
                                        const OpenSpB_vector vecX,
                                        const void *beta,
                                        OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_LBNEC_FP64(OpenSpB_operation_t op,
                                        const void *alpha,
                                        const OpenSpB_matrix matA,
                                        const OpenSpB_vector vecX,
                                        const void *beta,
                                        OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_LIGHT_FP64(OpenSpB_operation_t op,
                                        const void *alpha,
                                        const OpenSpB_matrix matA,
                                        const OpenSpB_vector vecX,
                                        const void *beta,
                                        OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_SpMV_flat_FP64(OpenSpB_operation_t op,
                                        const void *alpha,
                                        const OpenSpB_matrix matA,
                                        const OpenSpB_vector vecX,
                                        const void *beta,
                                        OpenSpB_vector vecY);

    OpenSpB_info OpenSpB_mxv(OpenSpB_vector y, const OpenSpB_matrix A, const OpenSpB_vector x, void *VNEC);

    /////////////////////////////////////////CPU kernel////////////////////////////////////////////
    // TODO: user APIs?
    void SpMV_VNEC_D_FP32(OpenSpB_vector y,
                          const OpenSpB_matrix A,
                          const OpenSpB_vector x,
                          VNEC_D_FP32 *mat_thd);

    struct VNEC_D_FP32 *Build_VNEC_D_FP32(const OpenSpB_matrix A);
    OpenSpB_VNEC_type IRD_VNEC(const OpenSpB_matrix A, OpenSpB_type type);

    void SpMV_VNEC_S_FP32(OpenSpB_vector y,
                          const OpenSpB_matrix A,
                          const OpenSpB_vector x,
                          VNEC_S_FP32 *mat_thd);

    struct VNEC_S_FP32 *Build_VNEC_S_FP32(const OpenSpB_matrix A);

    struct VNEC_L *Build_VNEC_L(const OpenSpB_matrix A);
    void SpMV_VNEC_L_FP32(OpenSpB_vector y, const OpenSpB_matrix A, const OpenSpB_vector x, VNEC_L *mat_thd);

    void SpMV_VNEC_D_FP64(OpenSpB_vector y,
                          const OpenSpB_matrix A,
                          const OpenSpB_vector x,
                          VNEC_D_FP64 *mat_thd);

    struct VNEC_D_FP64 *Build_VNEC_D_FP64(const OpenSpB_matrix A);

    void SpMV_VNEC_S_FP64(OpenSpB_vector y,
                          const OpenSpB_matrix A,
                          const OpenSpB_vector x,
                          VNEC_S_FP64 *mat_thd);

    struct VNEC_S_FP64 *Build_VNEC_S_FP64(const OpenSpB_matrix A);

    void SpMV_VNEC_L_FP64(OpenSpB_vector y, const OpenSpB_matrix A, const OpenSpB_vector x, VNEC_L *mat_thd);
    /**@}*/ // end for OpenSpB_mxv

    /**
     * @defgroup OpenSpB_mxm
     * @brief Matrix-Matrix multiplication module
     * @details This module mainly implements matrix and matrix multiplication operations. Since in the initial design, we only consider the matrix to be stored using sparse format, its core operator is SpGEMM.
     * @{
     */
    OpenSpB_info OpenSpB_mxm(OpenSpB_matrix Mat, const OpenSpB_matrix A, const OpenSpB_matrix B);
    /**@}*/ // end for OpenSpB_mxm

    /**
     * @defgroup OpenSpB_transpose
     * @brief Transpose rows and columns of a matrix.
     * @details This version computes a new matrix that is the transpose of the source matrix.
     * @{
     */

    /**
     * @brief Computes the transformation of the values of the elements of a vector using a unary function.
     *
     * @param[in,out] C An existing SparseBLAS matrix. On input, the matrix provides values that may be accumulated with the result of the transpose operation. On output, the matrix holds the results of the operation.
     * @param[in] A     The SparseBLAS matrix on which transposition will be performed.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_transpose(OpenSpB_matrix Mat, const OpenSpB_matrix A);
    /**@} */ // end for OpenSpB_transpose

    /**@}*/ // end for operator

    /**
     * @defgroup Extension
     * @brief Extend the SparseBLAS API with some functions that control the underlying runtime methods.
     * @{
     */

    /**
     * @defgroup ObjectFormat
     * @brief Object format control module
     * @details The following code shows the default format for setting the matrix construction:
     * \code
     * OpenSpB_object_format_ext format;
     * format.matrix_format = OpenSpB_csr;
     * OpenSpB_Global_Option_set_ext(OpenSpB_matrix_format, format);
     * \endcode
     * @{
     */

    /**
     * @brief Function to set the global default object format
     *
     * @param[in] field The field needs to be set
     * @param[in] value The value will be set for this field
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_Global_Option_set_ext // set a global default option
        (
            OpenSpB_option_field_ext field, // option to change
            OpenSpB_object_format_ext value // value to change it to
        );

    /**
     * @brief Creates a new vector with specified domain, size and format.
     *
     * @param[in,out] v On successful return, contains a handle to the newly created OpenSparseBLAS vector.
     * @param[in] type The type corresponding to the domain of the vector being created. Can be one of the predefined \link OpenSpB_type \enlink.
     * @param[in] n The size of the vector being created.
     * @param[in] format The format of the vector being created.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_vector_new_format_ext(OpenSpB_vector *v,
                                               OpenSpB_type type,
                                               OpenSpB_index n,
                                               OpenSpB_vector_format_value_ext format);

    /**
     * @brief Get the format of the given vector
     *
     * @param[in] v The OpenSparseBLAS vector which format will be retured
     * @return OpenSpB_vector_format_value_ext
     */
    OpenSpB_vector_format_value_ext OpenSpB_vector_format_ext(const OpenSpB_vector v);

    /**
     * @brief Creates a new vector in a way that copies the format of a given vector.
     * @details The new vector format will be the same as the format of the given vector, but will not copy its value.
     * @param out The new vector
     * @param in The given vector
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_vector_copy_format_ext(OpenSpB_vector *out, const OpenSpB_vector in);

    /**
     * @brief Creates a new matrix with specified domain, size and format.
     *
     * @param[in,out] v On successful return, contains a handle to the newly created OpenSparseBLAS matrix.
     * @param[in] type The type corresponding to the domain of the matrix being created. Can be one of the predefined \link OpenSpB_type \enlink.
     * @param[in] row The row number of the matrix being created.
     * @param[in] col The col number of the matrix being created.
     * @param[in] format The format of the matrix being created.
     * @return OpenSpB_info
     */
    OpenSpB_info OpenSpB_matrix_new_format_ext(OpenSpB_matrix *m,
                                               OpenSpB_type type,
                                               OpenSpB_index row,
                                               OpenSpB_index col,
                                               OpenSpB_matrix_format_value_ext format);

    /**
     * @brief Get the format of the given matrix
     *
     * @param[in] m The OpenSparseBLAS matrix which format will be retured
     * @return OpenSpB_matrix_format_value_ext
     */
    OpenSpB_matrix_format_value_ext OpenSpB_matrix_format_ext(const OpenSpB_matrix m);
    /**@}*/ // end for ObjectFormat

    /**
     * @brief Decide whether to print warning message.
     *
     */
    OpenSpB_info OpenSpB_Warning_switch_set_ext(bool val);
    /**@}*/ // end for Extension

#ifdef __cplusplus
}
#endif

// The declaration of C++ code
#ifdef __cplusplus

#define OpenSpB_VECTOR_EXTRACT_CPP(type, T) \
    OpenSpB_info OpenSpB_vector_extract_element(type *x, const OpenSpB_vector v, OpenSpB_index i);

OpenSpB_VECTOR_EXTRACT_CPP(bool, BOOL);
OpenSpB_VECTOR_EXTRACT_CPP(int8_t, INT8);
OpenSpB_VECTOR_EXTRACT_CPP(int16_t, INT16);
OpenSpB_VECTOR_EXTRACT_CPP(int32_t, INT32);
OpenSpB_VECTOR_EXTRACT_CPP(int64_t, INT64);
OpenSpB_VECTOR_EXTRACT_CPP(uint8_t, UINT8);
OpenSpB_VECTOR_EXTRACT_CPP(uint16_t, UINT16);
OpenSpB_VECTOR_EXTRACT_CPP(uint32_t, UINT32);
OpenSpB_VECTOR_EXTRACT_CPP(uint64_t, UINT64);
OpenSpB_VECTOR_EXTRACT_CPP(float, FP32);
OpenSpB_VECTOR_EXTRACT_CPP(double, FP64);
#undef OpenSpB_VECTOR_EXTRACT_CPP

#define OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(type, T) \
    OpenSpB_info OpenSpB_vector_extract_tuples(OpenSpB_index *RowInd, type *Vals, OpenSpB_index *p_nvals, const OpenSpB_vector v);

OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(bool, BOOL);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(int8_t, INT8);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(int16_t, INT16);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(int32_t, INT32);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(int64_t, INT64);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(uint8_t, UINT8);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(uint16_t, UINT16);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(uint32_t, UINT32);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(uint64_t, UINT64);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(float, FP32);
OpenSpB_VECTOR_EXTRACT_TUPLES_CPP(double, FP64);
#undef OpenSpB_VECTOR_EXTRACT_TUPLES_CPP

#define OpenSpB_VECTOR_SET_CPP(type, T) \
    OpenSpB_info OpenSpB_vector_set_element(OpenSpB_vector v, type x, OpenSpB_index i);

OpenSpB_VECTOR_SET_CPP(bool, BOOL);
OpenSpB_VECTOR_SET_CPP(int8_t, INT8);
OpenSpB_VECTOR_SET_CPP(int16_t, INT16);
OpenSpB_VECTOR_SET_CPP(int32_t, INT32);
OpenSpB_VECTOR_SET_CPP(int64_t, INT64);
OpenSpB_VECTOR_SET_CPP(uint8_t, UINT8);
OpenSpB_VECTOR_SET_CPP(uint16_t, UINT16);
OpenSpB_VECTOR_SET_CPP(uint32_t, UINT32);
OpenSpB_VECTOR_SET_CPP(uint64_t, UINT64);
OpenSpB_VECTOR_SET_CPP(float, FP32);
OpenSpB_VECTOR_SET_CPP(double, FP64);
#undef OpenSpB_VECTOR_SET_CPP

#include <stddef.h>     /* size_t */
typedef int blas_sparse_matrix;

/* Level 1 Computational Routines */
void OpenSpB_sdot(
    enum OpenSpB_conj_type conj, int nz, 
    const float *x, const int *indx, const float *y, int incy, float *r,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_ddot(
    enum OpenSpB_conj_type conj, int nz, 
    const double *x, const int *indx, 
    const double *y, int incy, 
    double *r,
    enum OpenSpB_base_type index_base 
);

void OpenSpB_cdot(
    enum OpenSpB_conj_type conj, int nz,
    const void *x,  const int *indx,
    const void *y,  int incy,
    void* r,
    enum OpenSpB_base_type index_base
);

void OpenSpB_zdot(
    enum OpenSpB_conj_type conj, int nz,
    const void* x, const int* indx,
    const void* y, int incy,
    void* r,
    enum OpenSpB_base_type index_base
);

void OpenSpB_saxpy(
    int nz,
    float alpha, 
    const float *x, const int *indx,
    float *y, int incy, 
    enum OpenSpB_base_type index_base
);


void OpenSpB_daxpy(
    int nz,
    double alpha, 
    const double *x, const int *indx,
    double *y, int incy, 
    enum OpenSpB_base_type index_base
);
void OpenSpB_caxpy(
    int nz,
    const void *alpha, 
    const void *x, const int *indx,
    void *y, int incy, 
    enum OpenSpB_base_type index_base
);

void OpenSpB_zaxpy(
    int nz, 
    const void *alpha, 
    const void *x, const int *indx,
    void *y, int incy, 
    enum OpenSpB_base_type index_base
);

void OpenSpB_sgather(
    int nz, 
    const float *y, int incy, 
    float *x, const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_dgather( 
    int nz, 
    const double *y, int incy, 
    double *x, const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_cgather( 
    int nz,
    const void *y, int incy,
    void *x, const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_zgather( 
    int nz, 
    const void *y, int incy, 
    void *x, const int *indx,
    enum OpenSpB_base_type index_base 
);

void OpenSpB_sgther_zero( 
    int nz, 
    float *y, int incy, 
    float *x, const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_dgther_zero( 
    int nz, 
    double *y, int incy, 
    double *x, const int *indx,
    enum OpenSpB_base_type index_base
);
void OpenSpB_cgther_zero( 
    int nz, 
    void *y, int incy, 
    void *x, const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_zgther_zero( 
    int nz, 
    void *y, int incy, 
    void *x, const int *indx,
    enum OpenSpB_base_type index_base 
);

void OpenSpB_sscatter( 
    int nz, 
    const float *x, 
    float *y, int incy, 
    const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_dscatter( 
    int nz, 
    const double *x, 
    double *y, int incy, 
    const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_cscatter( 
    int nz, 
    const void *x, 
    void *y, int incy, 
    const int *indx,
    enum OpenSpB_base_type index_base 
);
void OpenSpB_zscatter( 
    int nz, 
    const void *x, 
    void *y, int incy,
    const int *indx,
    enum OpenSpB_base_type index_base 
);


/* Level 2 Computational Routines */
int OpenSpB_strsv( 
    enum OpenSpB_trans_type transt, 
    float alpha, 
    blas_sparse_matrix T, 
    float *x, int incx 
);
int OpenSpB_dtrsv( 
    enum OpenSpB_trans_type transt, 
    double alpha, 
    blas_sparse_matrix T, 
    double *x, int incx 
);
int OpenSpB_ctrsv( 
    enum OpenSpB_trans_type transt, 
    const void *alpha, 
    blas_sparse_matrix T, 
    void *x, int incx 
);
int OpenSpB_ztrsv( 
    enum OpenSpB_trans_type transt, 
    const void *alpha, 
    blas_sparse_matrix T, 
    void *x, int incx 
);




OpenSpB_status OpenSpB_ssptrsv(int m,
                     const int *csc_col_ptr, 
                     const int *csc_row_ind,
                     const float *csc_vals,
                     float *x,
                     const float *b,
                     OpenSpB_base_type index_base,
                     OpenSpB_uplo_type uplo);

OpenSpB_status OpenSpB_dsptrsv(int m,
                     const int *csc_col_ptr, 
                     const int *csc_row_ind,
                     const double *csc_vals,
                     double *x,
                     const double *b,
                     OpenSpB_base_type index_base,
                     OpenSpB_uplo_type uplo);

OpenSpB_status OpenSpB_csptrsv(int m,
                     const int *csc_col_ptr, 
                     const int *csc_row_ind,
                     const void *csc_vals,
                     void *x,
                     const void *b,
                     OpenSpB_base_type index_base,
                     OpenSpB_uplo_type uplo);  
                     
OpenSpB_status OpenSpB_zsptrsv(int m,
                     const int *csc_col_ptr, 
                     const int *csc_row_ind,
                     const void *csc_vals,
                     void *x,
                     const void *b,
                     OpenSpB_base_type index_base,
                     OpenSpB_uplo_type uplo);  


OpenSpB_status OpenSpB_ssptrsm(   int m,
                                        int nrhs,
                                        const int*cp,
                                        const int*ri,
                                        const float*v,
                                        float*X,
                                        int ldx,
                                        const float*B,
                                        int ldb,
                                        OpenSpB_base_type base,
                                        OpenSpB_uplo_type uplo);

OpenSpB_status OpenSpB_dsptrsm(   int m,
                                        int nrhs,
                                        const int*cp,
                                        const int*ri,
                                        const double*v,
                                        double*X,
                                        int ldx,
                                        const double*B,
                                        int ldb,
                                        OpenSpB_base_type base,
                                        OpenSpB_uplo_type uplo);

OpenSpB_status OpenSpB_csptrsm(   int m,
                                        int nrhs,
                                        const int*cp,
                                        const int*ri,
                                        const void*v,
                                        void*X,
                                        int ldx,
                                        const void*B,
                                        int ldb,
                                        OpenSpB_base_type base,
                                        OpenSpB_uplo_type uplo);

OpenSpB_status OpenSpB_zsptrsm(   int m,
                                        int nrhs,
                                        const int*cp,
                                        const int*ri,
                                        const void* v,
                                        void*   X,
                                        int ldx,
                                        const void* B,
                                        int ldb,
                                        OpenSpB_base_type base,
                                        OpenSpB_uplo_type uplo);

                     
/* Level 3 Computational Routines */
void OpenSpB_scscmm(
    OpenSpB_trans_type transa,
    OpenSpB_base_type index_base,
    const int *m, const int *n, const int *k,
    const float *alpha,
    const int *columnPtra, const int *rowIndexa, const float *vala,
    const float *b, const int ldb,
    const float *beta,
    float *c, int ldc
);
void OpenSpB_dcscmm(
    OpenSpB_trans_type transa,
    OpenSpB_base_type index_base,
    const int *m, const int *n, const int *k,
    const double *alpha,
    const int *columnPtra, const int *rowIndexa, const double *vala,
    const double *b, const int ldb,
    const double *beta,
    double *c, int ldc
);
void OpenSpB_ccscmm(
    OpenSpB_trans_type transa,
    OpenSpB_base_type index_base,
    const int *m, const int *n, const int *k,
    const void *alpha,
    const int *columnPtra, const int *rowIndexa, const void *vala,
    const void *b, const int ldb,
    const void *beta,
    void *c, int ldc
);
void OpenSpB_zcscmm(
    OpenSpB_trans_type transa,
    OpenSpB_base_type index_base,
    const int *m, const int *n, const int *k,
    const void *alpha,
    const int *columnPtra, const int *rowIndexa, const void *vala,
    const void *b, const int ldb,
    const void *beta,
    void *c, int ldc
);



int OpenSpB_strsm( 
    enum OpenSpB_order_type order, enum OpenSpB_trans_type transt,
    int nrhs, 
    float alpha, 
    int t, 
    float *b, int ldb 
);
int OpenSpB_dtrsm( 
    enum OpenSpB_order_type order, enum OpenSpB_trans_type transt,
    int nrhs, 
    double alpha, 
    int t, 
    double *b, int ldb 
);
int OpenSpB_ctrsm(
    enum OpenSpB_order_type order, enum OpenSpB_trans_type transt,
    int nrhs, 
    const void *alpha, 
    int t, 
    void *b, int ldb 
);
int OpenSpB_ztrsm( 
    enum OpenSpB_order_type order, enum OpenSpB_trans_type transt,
    int nrhs, 
    const void *alpha, 
    int t, 
    void *b, int ldb 
);

#endif

/**
 * @defgroup algorithm
 * @brief The basic graph algorithms
 * @details This module contains a series of basic graph algorithms implemented using OpenSparseBLAS.
 *
 */
